public class Unit extends Tileable {
	Rally rally;
	public int clockStep;
	public int offensive;
	public int defensive;
	public int armor;
	public int movement;
	int moveDelay;
	public int health;
	public int upkeep;
	public int rawUpkeep;
	Player player;
	public int maxHealth;
	public int maxArmor;
	public String mode;
	public int powerDelay = 0;
	public RTSQueue<Character> movementQueue; // to be changed to Queue
	public RTSQueue<int[]> commandQueue; // to be changed to Queue
	public int ID;

	public Unit(int _id, Player player) {
		this.ID = _id;
		this.type = 0;
		this.player = player;
		this.mode = "STANDBY";
		this.movementQueue = new RTSQueue<Character>();
		this.commandQueue = new RTSQueue<int[]>();
		this.rally = null;
	}

	public void delCommands() {
		commandQueue.clear();
	}

	public void addCommand(int[] command) {
		commandQueue.put(command);
	}

	public String getCommandTxt() {
		if (commandQueue.getSize() > 0) {
			int[] command;
			command = commandQueue.peek();
			switch (command[0]) {
			case 0:
				return "Go to rally " + command[1];
			case 4:
				return "Build base in " + command[1];
			case 5:
				return "Build farm in " + command[1];
			default:
				return "Idle";
			}
		} else {
			return "Idle";
		}
	}

	public void getCommand(Map m) {
		int[] command;
		if (commandQueue.getSize() > 0) {
			command = commandQueue.peek();
			if (command[0] == 0) {
				if (player.rally[command[1]] != null) {
					this.targetX = player.rally[command[1]].getX();
					this.targetY = player.rally[command[1]].getY();
					if ((this.x == this.targetX) && (this.y == this.targetY)) {
						player.rally[command[1]].addUnit(this);
						commandQueue.pop();
						getCommand(m);
					} else {
						this.moveDelay--;
						if (this.moveDelay <= 0) {
							move(m, targetX, targetY);
							if ((this.x == this.targetX)
									&& (this.y == this.targetY)) {
								player.rally[command[1]].addUnit(this);
								commandQueue.pop();
								getCommand(m);
							}
							this.moveDelay = this.movement;
						}

					}

				} else {
					commandQueue.pop();
					getCommand(m);
				}

			} else if (command[0] == 4) // make new Base
			{
				if (command[1] != 0) {
					this.mode = "WORKING"; // working mode, full upkeep
					this.upkeep = this.rawUpkeep;
					command[1]--;
				} else {
					this.mode = "STANDBY"; // back to standby
					this.upkeep = this.rawUpkeep * 3 / 4;
					player.makeBase(m.getTile(this.x, this.y));
					commandQueue.pop();
				}

			} else if (command[0] == 5) // make new Farm
			{
				if (command[1] != 0) {
					this.mode = "WORKING";
					this.upkeep = this.rawUpkeep; // working mode, full upkeep
					command[1]--;
				} else {
					this.mode = "STANDBY"; // back to standby
					this.upkeep = this.rawUpkeep * 3 / 4;
					player.makeFarm(m.getTile(this.x, this.y));
					commandQueue.pop();
				}

			}
		}
	}

	public Rally getRally() {
		return this.rally;
	}

	public void setRally(Rally rally) {
		this.rally = rally;
	}

	public int[] getStatus() {
		int[] status = new int[10];
		status[0] = this.ID;
		status[1] = this.type;
		status[2] = this.offensive;
		status[3] = this.defensive;
		status[4] = this.armor;
		status[5] = this.movement;
		status[6] = this.health;
		status[7] = this.upkeep;
		status[8] = this.player.getID();
		if (this.rally != null) {
			status[9] = this.rally.getID();
		} else {
			status[9] = -1;
		}
		return status;
	}

	public int getOffensive() {
		return this.offensive;
	}

	public int getDefensive() {
		return this.defensive;
	}

	public int getArmor() {
		return this.armor;
	}

	public int getMovement() {
		return this.movement;
	}

	public int getHealth() {
		return this.health;
	}

	public int getUpkeep() {
		return this.upkeep;
	}

	public int getPlayerID() {
		return this.player.getID();
	}

	public int getRallyID() {
		return this.rally.getID();
	}

	public int getMaxHealth() {
		return this.maxHealth;
	}

	public String[] gettxtStatus() {
		String[] status = new String[10];
		status[0] = this.getTypeName(this.type);
		status[1] = "ID: " + this.ID;
		if (this.getRally() == null) {
			status[2] = "Rally:";
		} else {
			status[2] = "Rally: " + this.getRally().getID();
		}
		status[3] = "DMG: " + this.offensive;
		status[4] = "DEF: " + this.defensive;
		status[5] = "Armor: " + this.armor;
		status[6] = "Movement: " + this.movement;
		status[7] = "HP: " + this.health;
		status[8] = "Upkeep: " + this.upkeep;
		status[9] = "" + this.mode;
		return status;
	}

	public String[] gettxtCommands() {
		String[] commands = { "Go to rally", "Decommission", "Power down",
				"Power up" };
		return commands;
	}

	public void incHealth() {
		// int temp=this.health;
		/*
		 * if(temp < this.maxHealth) { temp+=10; if(temp>this.maxHealth) temp =
		 * this.maxHealth; }
		 * 
		 * this.health = temp;
		 */
		this.health += 10;
	}

	public void incArmor() {
		/*
		 * int temp=this.armor; if(temp < this.maxArmor) { temp+=10;
		 * if(temp>this.maxArmor) temp = this.maxArmor; } this.armor = temp;
		 */
		this.armor += 1;
	}

	public void weaken(int dec) {
		if (this.health > 0)
			this.health -= dec;
	}

	public void destroy() {
		this.health = 0;
	}

	public void powerDown() {
		if (this.mode != "SLEEP") {
			this.powerDelay = 10;
		}
		this.mode = "SLEEP";
		this.upkeep = rawUpkeep / 4;
	}

	public void powerUp() {
		if (this.mode == "SLEEP") {
			this.mode = "POWERING UP";
		} else {
			this.mode = "STANDBY";
		}
		this.upkeep = rawUpkeep * 3 / 4;
	}

	private int ss, gg, a, b;
	private int[] s, g;

	public void setDestination(int _x, int _y) {
		if ((targetX + _x) >= 0 && (targetX + _x) < 29 && (targetY + _y) >= 0
				&& (targetY + _y) < 29) {
			this.targetX += _x;
			this.targetY += _y;
		}
	}

	public void doMove(Map m) {
		player.consumeFood(this.upkeep);
		
		if(this.type==0 && m.getTile(this.x,this.y).hasResource())
		{
			Resource r=m.getTile(this.x,this.y).getResource();
			((Explorer)this).getResource(r);
			
		}
		if (this.powerDelay > 0) {
			if (this.mode != "SLEEP") {
				this.powerDelay--;
				if (this.powerDelay == 0) {
					this.mode = "STANDBY";
				}
			}
		} else {
			getCommand(m);
		}
	}

	public int move(Map m, int x, int y) {
		char c1 = '-', c2 = '-';
		int w = m.width();
		int numOfElem = w * m.height();
		s = new int[numOfElem];
		g = new int[numOfElem];
		for (int i = 0; i < numOfElem; i++) {
			s[i] = -1;
			g[i] = -1;
			char ch = m.getTileLabel(i % w, i / w);
			if (ch == '*' || ch == '&')
				s[i] = -2;
			if (i % w == getX() && i / w == getY()) {
				ss = i;
			}
			if (i % w == x && i / w == y) {
				gg = i;
			}
		}
		a = gg;
		b = gg;
		while (a != ss) {
			add(a, 1);
			add(a, -1);
			add(a, w);
			add(a, -w);
			a = s[a];
		}

		int count = 0;
		while (a != gg) {
			if (count == 0)
				c1 = sv(g[a]);
			else if (count == 1)
				c2 = sv(g[a]);
			count++;
			a += g[a];
		}

		int dir = evalDirection(c1, c2);

		switch (dir) {
		case 1:
			m.displace(this.x, this.y, this.x - 1, this.y + 1, this);
			break;
		case 2:
			m.displace(this.x, this.y, this.x - 0, this.y + 1, this);
			break;
		case 3:
			m.displace(this.x, this.y, this.x + 1, this.y + 1, this);
			break;
		case 4:
			m.displace(this.x, this.y, this.x - 1, this.y + 0, this);
			break;
		case 6:
			m.displace(this.x, this.y, this.x + 1, this.y + 0, this);
			break;
		case 7:
			m.displace(this.x, this.y, this.x - 1, this.y - 1, this);
			break;
		case 8:
			m.displace(this.x, this.y, this.x - 0, this.y - 1, this);
			break;
		case 9:
			m.displace(this.x, this.y, this.x + 1, this.y - 1, this);
			break;
		default:
			m.displace(this.x, this.y, this.x + 0, this.y + 0, this);
		}
		Tile tempTile = m.getTile(this.x, this.y);

		if (tempTile.hasItem()) {

			Item it = tempTile.getItem();
			int itType = it.getType();
			if (itType == 40) {
				this.incHealth();
				Item[] iArray = it.getItemArray();
				iArray[it.getIndex()] = null;
			}

			else if (itType == 41) {
				this.incArmor();
				Item[] iArray = it.getItemArray();
				iArray[it.getIndex()] = null;
			}

			tempTile.deleteItem();

		}
		if (tempTile.hasAreaEffect()) {

			AreaEffect ae = tempTile.getAreaEffect();
			int aeType = ae.getType();
			if (aeType == 60) {
				this.health-=5;
				
			}

			else if (aeType == 61) {
				this.health+=5;
			}
			else if( aeType== 62){
				this.player.destroyUnit(this.getStatus()[0]);
			}
		}
		return dir;
	}

	private int evalDirection(char c1, char c2) {
		int dir = -1;
		if ((c1 == 'N' && c2 == 'N') || (c1 == 'N' && c2 == '-'))
			dir = 8;
		else if ((c1 == 'W' && c2 == 'W') || (c1 == 'W' && c2 == '-'))
			dir = 4;
		else if ((c1 == 'S' && c2 == 'S') || (c1 == 'S' && c2 == '-'))
			dir = 2;
		else if ((c1 == 'E' && c2 == 'E') || (c1 == 'E' && c2 == '-'))
			dir = 6;
		else if ((c1 == 'E' && c2 == 'N') || (c1 == 'N' && c2 == 'E'))
			dir = 9;
		else if ((c1 == 'E' && c2 == 'S') || (c1 == 'S' && c2 == 'E'))
			dir = 3;
		else if ((c1 == 'W' && c2 == 'N') || (c1 == 'N' && c2 == 'W'))
			dir = 7;
		else if ((c1 == 'W' && c2 == 'S') || (c1 == 'S' && c2 == 'W'))
			dir = 1;
		else
			dir = -1;
		return dir;
	}

	private void add(int p, int o) {
		if (p + o > -1) {
			if (s[p + o] == -1) {
				s[b] = p + o;
				b = p + o;
				g[p + o] = -o;
			}
		}
	}

	private char sv(int o) {
		if (o > 0)
			return (o == 1) ? 'E' : 'S';
		return (o == -1) ? 'W' : 'N';
	}

}
